package com.zyj.benchmark.sample;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;

import java.util.concurrent.TimeUnit;

@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class Sample_16_CompilerControl {

    /**
     * 我们可以通过hotspot的一些功能,去告诉编译器, 我们想如何优化我们的代码
     * 第一个方法: 禁止使用内联优化
     * 第二个方法: 强制使用内联优化
     * 第三个方法: 禁止编译
     */

    /**
     * 方法内联可以消除方法调用的成本
     * 你如果分为多个方法, JVM总要去方法区去找将要调用的方法吧, 总要去做一些参数指针的复制吧, 寄存器肯定会被反复操作, 自然就慢下来了
     * 那JIT会对代码进行分析, 对于频繁调用的方法会进行内联的优化
     * 那么未内联的和内联的代码执行起来性能就会发生差距, 但逻辑却一致
     * ---
     * 那么我们这个测试有什么用呢?
     * 我们可以知道我们写的代码在内联能给我们提升多大优势
     * 有些代码是不能内联的, 因为实现类可能是参数传入的, 那么JVM就不会对其进行优化
     * 但如果我们JMH进行测试, 内联能给我们的功能较大的提升, 那么我们就要想办法优化代码, 让JVM可以对其进行内联优化
     */

    public void target_blank() {
    }

    @CompilerControl(CompilerControl.Mode.DONT_INLINE) //不使用内联
    public void target_dontInline() {
    }

    @CompilerControl(CompilerControl.Mode.INLINE) //强制使用内联
    public void target_inline() {
    }

    @CompilerControl(CompilerControl.Mode.EXCLUDE)
    public void target_exclude() {
    }

    @Benchmark
    public void baseline() {
    }

    @Benchmark
    public void blank() {
        target_blank();
    }

    @Benchmark
    public void dontinline() {
        target_dontInline();
    }

    @Benchmark
    public void inline() {
        target_inline();
    }

    @Benchmark
    public void exclude() {
        target_exclude();
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(Sample_16_CompilerControl.class.getSimpleName())
                .warmupIterations(0)
                .measurementIterations(1)
                .measurementTime(TimeValue.seconds(1))
                .forks(1)
                .build();

        new Runner(opt).run();
    }


}
